package com.anli02.service.impl;




import cn.hutool.json.JSON;
import com.anli02.Callback.UploadCallback;
import com.anli02.FileStorage.FileStorageService;
import com.anli02.entity.dto.SessionwebUserDto;
import com.anli02.entity.dto.UpdateArticleMess;
import com.anli02.entity.enums.HotArticleConstants;
import com.anli02.entity.enums.OnlineMusicField;
import com.anli02.entity.pojo.OnlineMusic;
import com.anli02.entity.vo.OnlineMusicDoc;
import com.anli02.entity.vo.R;

import com.anli02.exception.BusinessException;
import com.anli02.mapper.OnlineMusicMapper;
import com.anli02.service.IOnlineMusicService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.core.io.InputStreamResource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.concurrent.ListenableFutureCallback;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.StringWriter;
import java.math.BigDecimal;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.elasticsearch.common.geo.GeoPoint;


/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author author
 * @since 2024-10-08
 */
@Service
public class OnlineMusicServiceImpl extends ServiceImpl<OnlineMusicMapper, OnlineMusic> implements IOnlineMusicService {

    @Autowired
RedisTemplate redisTemplate;
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private Configuration configuration;
    @Override
    public R upload(MultipartFile file, String musicName, BigDecimal latitude, BigDecimal longitude) {
       //
        SessionwebUserDto sessionwebUserDto = (SessionwebUserDto) RequestContextHolder.getRequestAttributes().getAttribute("user", RequestAttributes.SCOPE_REQUEST);

        OnlineMusic onlineMusic=new OnlineMusic();
        if(file.isEmpty()||musicName.isEmpty()||latitude==null||longitude==null)
        {
            throw new BusinessException(500,"参数错误");
        }
        if(file.getSize()>1024*1024*50)
        {
            throw new BusinessException(500,"文件过大");
        }

        //异步线程池上传文件
        String fileid=new String();
        onlineMusic.setMusicName(musicName);
        onlineMusic.setLongitude(longitude);
        onlineMusic.setLatitude(latitude);
        onlineMusic.setUserid(sessionwebUserDto.getUserId());
            try {
                //修改为mq--发送mq信息
                Random random = new Random();
                String uuid = String.valueOf(Math.abs(random.nextLong()));  // 确保为非负数

                fileupload(file, uuid, new UploadCallback() {

                    @Override
                    public void onSuccess(String uuid) {

                    }

                    @Override
                    public void onFailure(Exception e) {
                        // 上传失败的处理
                        throw new BusinessException(500, "文件上传失败: " + e.getMessage());
                    }
                });

        }catch (Exception e)
        {
            throw new BusinessException(500,"文件上传失败");
        }

        if(fileid.isEmpty())
        {
          throw  new BusinessException(500,"文件上传失败");
        }
        onlineMusic.setFileLocation(fileid);
        onlineMusic.setUploadDate(LocalDate.now());
        boolean q=save(onlineMusic);
        if(!q)
        {
            //删除本地文件了--没写
            throw  new BusinessException(500,"文件上传失败");
        }
        ///全部异步

        //1 评论 2 代表播放 3 代表点赞
        redisTemplate.opsForHash().put("onlineMusic:" + onlineMusic.getMusic(), OnlineMusicField.PLAY_COUNT.getFieldCode(), 0);
        redisTemplate.opsForHash().put("onlineMusic:" + onlineMusic.getMusic(), OnlineMusicField.LIKE_COUNT.getFieldCode(), 0);
        redisTemplate.opsForHash().put("onlineMusic:" + onlineMusic.getMusic(), OnlineMusicField.COMMENT_COUNT.getFieldCode(), 0);
        redisTemplate.opsForHash().put("onlineFile:" + onlineMusic.getFileLocation(), OnlineMusicField.FILE_ID.getFieldCode(), onlineMusic.getMusic());

       rabbitTemplate.convertAndSend("music","music_key",onlineMusic);

       //静态化测试
        try {
            Template template = configuration.getTemplate("02-list.ftl");
             Map<String, Object> dataModel = new HashMap<>();
             dataModel.put("music", onlineMusic);
            StringWriter out = new StringWriter();
            template.process(dataModel, out);
            InputStream is = new ByteArrayInputStream(out.toString().getBytes());
            fileStorageService.uploadHtmlFile("",onlineMusic.getMusic()+".html",is);

        }catch (Exception e)
        {
            throw new BusinessException(500,"静态化失败");
        }

        return R.success(onlineMusic);

    }
    @Autowired
    FileStorageService fileStorageService;
    @Autowired
    KafkaTemplate kmsTemplate;

    @Override
    public ResponseEntity<?> bofang(String id) {
        String MusicId  = (String) redisTemplate.opsForHash().get("onlineFile" + id, OnlineMusicField.FILE_ID.getFieldCode());
        Path dir = Paths.get("I:\\mp3\\");
        String pattern = id + "*";  // 使用 id + 通配符的方式匹配文件
        HttpHeaders headers = null;
        InputStreamResource resource = null;
        try {
            try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, pattern)) {
                Iterator<Path> iterator = stream.iterator();
                if (iterator.hasNext()) {
                    Path matchedFile = iterator.next();
                    //取第一个 优化思路 id+后缀 存redis-我uuid随机生成
                    //重复改了极其低-但是如果大项目就需要考虑了
                     headers = new HttpHeaders();
                    headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM_VALUE);  // 改为音频文件类型
                    headers.add(HttpHeaders.CONTENT_TYPE, "audio/mpeg"); // 设置正确的音频类型
                    resource = new InputStreamResource(Files.newInputStream(matchedFile));
                }
            }

        } catch (Exception e) {
            throw new BusinessException(500, "文件不存在");
        }

        String mucisId = String.valueOf(redisTemplate.opsForHash().increment("onlineMusic:" + MusicId, OnlineMusicField.PLAY_COUNT.getFieldCode(), 1));
        UpdateArticleMess mess=new UpdateArticleMess();
        mess.setMusicid(MusicId);
        mess.setAdd(1);
        mess.setType(UpdateArticleMess.UpdateArticleType.VIEWS);
        CorrelationData cd = new CorrelationData();
        cd.getFuture().addCallback(new ListenableFutureCallback<CorrelationData.Confirm>()
                                   {
                                       @Override
                                       public void onFailure(Throwable throwable) {
                                           // 处理失败的情况
                                           throwable.printStackTrace();
                                       }

                                       @Override
                                       public void onSuccess(CorrelationData.Confirm confirm) {
                                           // 处理成功的情况
                                        if(confirm.isAck())
                                            System.out.println("消息发送成功");
                                        else
                                            System.out.println("消息发送失败");
                                       }
                                   }

        );




        kmsTemplate.send( HotArticleConstants.HOT_ARTICLE_AGGREGATION_QUEUE,mess,cd);
        return ResponseEntity.ok()
                .headers(headers)
                .body(resource);
    }









    @Autowired
    RestHighLevelClient restHighLevelClient;

    @Override
    public R show(OnlineMusic onlineMusic) {
        //根据redis-从分值开始拿出推荐-缺点就是一直固定
        /// redisTemplate.opsForZSet().add(HotArticleConstants.HOT_ARTICLE_REDIS_QUEUE,mess.getMuicid(),score);
        //1 10 2 20 3 30
        //降序reverseRange 升序 range

        Set<String> set = redisTemplate.opsForZSet().reverseRange(HotArticleConstants.HOT_ARTICLE_REDIS_QUEUE, onlineMusic.getPage() * 10 - 10, onlineMusic.getPage() * 10);
        //数据来自es-两个搜索-带坐标附加-不带就是推荐

        OnlineMusicDoc doc = new OnlineMusicDoc(onlineMusic);
        GeoPoint geoPoint = new GeoPoint(doc.getLocation());
        SearchRequest request = new SearchRequest("online_music_index");
        if(doc.getLocation().isEmpty())
        {
            //首页搜索

            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.query(QueryBuilders.termsQuery("music", set)); // 使用文档ID字段

            request.source(searchSourceBuilder);
            try {
                SearchResponse search = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            }catch(Exception e)
            {
                e.printStackTrace();
            }

        }else
        {
            //附加推荐搜索

            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
            sourceBuilder.sort(SortBuilders.geoDistanceSort("location", geoPoint)
                    .order(SortOrder.ASC)  // 按距离升序排序
                    .unit(org.elasticsearch.common.unit.DistanceUnit.KILOMETERS));  // 单位为公里
            sourceBuilder.query(QueryBuilders.termsQuery("music", set)); // 使用文档ID字段
            request.source(sourceBuilder);
        }
        List<Map<String, Object>> resultList = new ArrayList<>();
        //解析es
        try {


            SearchResponse search = restHighLevelClient.search(request, RequestOptions.DEFAULT);

            // 获取 hits
            SearchHit[] hits = search.getHits().getHits();
            for (SearchHit hit : hits) {
                Map<String, Object> sourceAsMap = hit.getSourceAsMap();
                resultList.add(sourceAsMap);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }




        /*
        ps:应该由es直接提供，es本身就能计算分值
         */

        return R.success(resultList);
    }





























    //也不设计线程池-设计

    private final ExecutorService executorService = Executors.newFixedThreadPool(10); // 定义一个固定大小的线程池
    private Future<?> fileupload(MultipartFile file, String uuid, UploadCallback callback) {
        return executorService.submit(() -> {
            try {
                Path destinationFile = Paths.get("I:\\mp3\\" + uuid + "." + file.getContentType().split("/")[1]);
                // 存储文件
                Files.copy(file.getInputStream(), destinationFile);

            } catch (Exception e) {
                //调用回调
                callback.onFailure(e);

            }
        });
    }


}
